package com.x.compute.core.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.googlecode.aviator.lexer.token.OperatorType;
import com.x.compute.common.constant.VarTypeEnum;
import com.x.compute.core.context.VariableContext;
import com.x.compute.core.entity.*;
import com.x.compute.core.handle.ColumnVarHandleFactory;
import com.x.compute.core.handle.column.ColumnVarHandle;
import com.x.compute.core.mapper.ComputeMapper;
import com.x.compute.core.service.ComputeService;
import com.x.compute.core.service.ComputeTempService;
import com.x.compute.common.util.ComputeUtils;
import com.x.compute.core.util.ValidationUtils;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;


@Log4j2
@Service
public class ComputeServiceImpl extends ServiceImpl<ComputeMapper, Compute> implements ComputeService {

    @Resource
    private ComputeTempService computeTempService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, ComputeValue> addCompute(Long formId, ComputeParam... param) {
        return addCompute(false, formId, param);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, ComputeValue> addCompute(Long formId, List<ComputeParam> paramList) {
        return addCompute(false, formId, paramList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, ComputeValue> addCompute(boolean temp, Long formId, ComputeParam... param) {
        return addCompute(temp, formId, Arrays.asList(param));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, ComputeValue> addCompute(boolean temp, Long formId, List<ComputeParam> paramList) {
        return calculateHandle(formId, paramList, false, temp, true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, ComputeValue> updateCompute(Long formId, ComputeParam... param) {
        return updateCompute(false, formId, param);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, ComputeValue> updateCompute(Long formId, List<ComputeParam> paramList) {
        return updateCompute(false, formId, paramList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, ComputeValue> updateCompute(boolean temp, Long formId, ComputeParam... param) {
        return updateCompute(temp, formId, Arrays.asList(param));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, ComputeValue> updateCompute(boolean temp, Long formId, List<ComputeParam> paramList) {
        return calculateHandle(formId, paramList, true, temp, true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCompute(Long formId, String tableId, Long businessId) {
        deleteCompute(false, formId, tableId, businessId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCompute(boolean temp, Long formId, String tableId, Long businessId) {
        Set<Long> businessIds = new HashSet<>();
        businessIds.add(businessId);
        deleteCompute(temp, formId, tableId, businessIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCompute(Long formId, String tableId, Set<Long> businessIds) {
        deleteCompute(false, formId, tableId, businessIds);
    }

    /**
     * 删除计算变量逻辑流程：
     * 1、查询引用此计算字段的其他变量
     * 2、判断变量是否存在（除汇总字段外），true则抛出异常并结束
     * 3、移除汇总变量中的引用并重新计算新值
     * 4、判断此计算字段是否属于列计算字段，true则移除引用变量值中的数据
     * 5、批量修改发生改变的计算字段
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCompute(boolean temp, Long formId, String tableId, Set<Long> businessIds) {
        if (CollectionUtil.isEmpty(businessIds)) {
            return;
        }
        Set<String> businessIdsStr = businessIds.stream().map(businessId -> businessId.toString()).collect(Collectors.toSet());
        List<Compute> computeList = baseMapper.listByBusinessIds(formId, businessIdsStr, temp);
        if (CollectionUtil.isEmpty(computeList)) {
            return;
        }
        Map<String, Compute> preComputeMap = new HashMap<>();
        Date current = new Date();
        computeList.forEach(compute -> {
            preComputeMap.put(compute.getVarFullName(), compute);
            compute.setDeleted(true).setUpdateTime(current);
        });
        Set<String> preVars = new HashSet<>(preComputeMap.keySet());
        List<Compute> sufComputeList = baseMapper.listSufVars(formId, preVars, temp);
        if (CollectionUtil.isNotEmpty(sufComputeList)) {
            Set<String> rowSumVars = VariableContext.tableRelColumnSumVarMap.get(tableId);
            sufVarDeleteHandle(rowSumVars, preVars, preComputeMap, sufComputeList, computeList);
        }
        deleteBatchByIds(temp, computeList);
        //列变量处理
        Map<String, Map<String, Object>> columnVarMap = new HashMap<>();
        VariableContext.tableRelColumnVarMap.get(tableId).forEach(columnVarFullName ->{
            columnVarMap.put(columnVarFullName, null);
        });
        columnVarUpdateHandle(formId, columnVarMap, true, businessIdsStr, temp);
    }

    @Override
    public Map<String, String> getVarValue(Long formId, String...businessId) {
        return getVarValue(formId, Arrays.asList(businessId));
    }

    @Override
    public Map<String, String> getVarValue(boolean temp, Long formId, String businessId) {
        List<String> businessIds = new ArrayList<>();
        businessIds.add(businessId);
        return getVarValue(temp, formId, businessIds);
    }

    @Override
    public Map<String, String> getVarValue(Long objId, List<String> businessIds) {
        return getVarValue(false, objId, businessIds);
    }

    @Override
    public Map<String, String> getVarValue(boolean temp, Long formId, List<String> businessIds) {
        if (CollectionUtil.isEmpty(businessIds)) {
            return Collections.EMPTY_MAP;
        }
        List<Compute> computeList = baseMapper.listVarValueByBusinessIds(formId, businessIds, temp);
        return computeList.stream().collect(Collectors.toMap(Compute::getVarFullName, Compute::getVarValue));
    }

    @Override
    public Map<Long, String> getVarValue(Long... id) {
        return getVarValue(Arrays.asList(id));
    }

    @Override
    public String getVarValue(Long id, boolean temp) {
        List<Long> ids = new ArrayList<>();
        ids.add(id);
        return getVarValue(ids, temp).get(id);
    }

    @Override
    public Map<Long, String> getVarValue(List<Long> ids) {
        return getVarValue(ids, false);
    }

    @Override
    public Map<Long, String> getVarValue(List<Long> ids, boolean temp) {
        if (CollectionUtil.isEmpty(ids)) {
            return Collections.EMPTY_MAP;
        }
        List<Compute> computeList = baseMapper.listVarValueByIds(ids, temp);
        return computeList.stream().collect(Collectors.toMap(Compute::getId, Compute::getVarValue));
    }

    @Override
    public Map<String, Compute> getCompute(Long formId, String...businessId) {
        return getCompute(formId, Arrays.asList(businessId));
    }

    @Override
    public Map<String, Compute> getCompute(Long formId, String businessId, boolean temp) {
        List<String> businessIds = new ArrayList<>();
        businessIds.add(businessId.toString());
        return getCompute(formId, businessIds, temp);
    }

    @Override
    public Map<String, Compute> getCompute(Long formId, List<String> businessIds) {
        return getCompute(formId, businessIds, false);
    }

    @Override
    public Map<String, Compute> getCompute(Long formId, List<String> businessIds, boolean temp) {
        if (CollectionUtil.isEmpty(businessIds)) {
            return Collections.EMPTY_MAP;
        }
        List<Compute> computeList = baseMapper.listByBusinessIds(formId, businessIds, temp);
        return computeList.stream().collect(Collectors.toMap(Compute::getVarFullName, Function.identity()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitComputeTemp(Long formId) {
        List<Compute> computeList = baseMapper.listComputeTemp(formId);
        saveOrUpdateBatch(computeList);
        clearComputeTemp(formId);
    }

    @Override
    public void clearComputeTemp(Long formId) {
        computeTempService.remove(new LambdaQueryWrapper<ComputeTemp>().eq(ComputeTemp::getFormId, formId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<Long, Long> copyCompute(Long sourceFormId, Long targetFormId, Map<String, String> businessIdMap) {
        List<Compute> computeList = baseMapper.selectList(new LambdaQueryWrapper<Compute>()
                .eq(Compute::getFormId, sourceFormId)
                .eq(Compute::getDeleted, false));
        if (CollectionUtil.isEmpty(computeList)){
            return Collections.EMPTY_MAP;
        }
        Date current = new Date();
        Map<Long, Long> idMap = new HashMap<>();
        computeList.forEach(compute -> {
            Long id = IdUtil.getSnowflakeNextId();
            idMap.put(compute.getId(), id);
            compute.setId(id).setFormId(targetFormId).setCreateTime(current).setUpdateTime(current);
            //更新businessId
            String businessId = compute.getBusinessId();
            if (StrUtil.isNotBlank(businessId)){
                compute.setBusinessId(businessIdMap.get(businessId));
            }
            //更新expression
            String expression = compute.getExpression();
            if (StrUtil.isNotBlank(expression)) {
                expression = getReplaceString(businessIdMap, expression);
                compute.setExpression(expression);
            }
            //更新referenceVar
            String referenceVar = compute.getReferenceVar();
            if (StrUtil.isNotBlank(referenceVar)) {
                referenceVar = getReplaceString(businessIdMap, referenceVar);
                compute.setReferenceVar(referenceVar);
            }
            //更新referenceValueMap
            String referenceValueMap = compute.getReferenceValueMap();
            if (StrUtil.isNotBlank(referenceValueMap)) {
                referenceValueMap = getReplaceString(businessIdMap, referenceValueMap);
                compute.setReferenceValueMap(referenceValueMap);
            }
            //更新referenceValueMap
            String originalExpression = compute.getOriginalExpression();
            if (StrUtil.isNotBlank(originalExpression)) {
                originalExpression = getReplaceString(businessIdMap, originalExpression);
                compute.setOriginalExpression(originalExpression);
            }
        });
        return idMap;
    }


    /**
     * 批量删除计算变量
     * @param temp
     * @param computeList
     */
    private void deleteBatchByIds(boolean temp, List<Compute> computeList) {
        if (temp) {
            List<Long> ids = computeList.stream().map(Compute::getId).collect(Collectors.toList());
            computeTempService.removeBatchByIds(ids);
        } else {
            updateBatchById(computeList);
        }
    }

    /**
     * 列求和变量处理
     * @param formId
     * @param compute
     * @param tableRelColumnSumVarMap
     * @param sumVarParamList
     */
    public void columnSumVarHandle(Long formId,
                                   Compute compute,
                                   Map<String, List<Compute>> tableRelColumnSumVarMap,
                                   List<ComputeParam> sumVarParamList) {
        if (sumVarParamList == null){
            return;
        }
        Set<String> columnSumVarSet = VariableContext.tableRelColumnSumVarMap.get(compute.getTableId());
        if (CollectionUtil.isEmpty(columnSumVarSet)){
            //表格下没有列求和变量
            return;
        }
        List<Compute> sumComputeList = tableRelColumnSumVarMap.get(compute.getTableId());
        if (sumComputeList == null){
            sumComputeList = baseMapper.selectList(new QueryWrapper<Compute>().lambda()
                                        .eq(Compute::getFormId, formId)
                                        .eq(Compute::getTableId, compute.getTableId())
                                        .in(Compute::getVarFullName, columnSumVarSet)
                                        .eq(Compute::getDeleted, false));
            tableRelColumnSumVarMap.put(compute.getTableId(), sumComputeList);
        }
        String sumVarFullName = ComputeUtils.getColumnSumVarFullName(compute.getTableId(), compute.getVar());
        sumComputeList.forEach(sumCompute -> {
            if (!sumCompute.getVarFullName().equals(sumVarFullName)){
                return;
            }
            List<String> variables = new ArrayList<>();
            if (StrUtil.isNotBlank(sumCompute.getExpression())){
                variables.addAll(Arrays.asList(sumCompute.getExpression().split("\\" + OperatorType.ADD.token)));
            }
            variables.add(compute.getVarFullName());
            String expression = String.join(OperatorType.ADD.token, variables);
            expression = StrUtil.isBlank(expression) ? VarTypeEnum.NUMBER.defaultValue.toString() : expression;
            ComputeParam computeParam = ComputeParam.builder()
                                                    .id(sumCompute.getId())
                                                    .tableId(sumCompute.getTableId())
                                                    .var(sumCompute.getVar())
                                                    .varType(sumCompute.getVarType())
                                                    .expression(expression)
                                                    .build();
            sumVarParamList.add(computeParam);
        });
    }

    /**
     * 字符串替换
     *
     * @param replaceMap
     * @param str
     * @return
     */
    private static String getReplaceString(Map<String, String> replaceMap, String str) {
        for (Map.Entry<String, String> entry : replaceMap.entrySet()) {
            str = str.replace(entry.getKey(), entry.getValue());
        }
        return str;
    }

    /**
     * 计算表达式处理
     * - 新增：初始化参数 -> 前置变量查询处理 -> 批量保存和修改
     * - 修改：初始化参数 -> 计算数据比对校验 -> 前置变量查询处理 -> 后置变量查询处理 -> 批量修改
     *
     * @param formId    表单id
     * @param paramList 计算参数集合
     * @param update    是否修改
     * @param temp      是否临时计算
     * @param validate  是否校验计算参数
     * @return
     */
    private Map<String, ComputeValue> calculateHandle(Long formId,
                                                      List<ComputeParam> paramList,
                                                      boolean update,
                                                      boolean temp,
                                                      boolean validate) {
        Map<String, ComputeValue> computeValueMap = new HashMap<>();
        if (CollectionUtil.isEmpty(paramList)) {
            return computeValueMap;
        }
        //初始化表单下所有的列求和变量
        initColumnSumVar(formId);
        //前置变量集
        Map<String, List<String>> preVarsMap = new HashMap<>();
        //用于保存内存变量
        Map<String, Compute> preComputeMap = new HashMap<>();
        //列变量集
        Map<String, Map<String, Object>> columnVarMap = new HashMap<>();
        //初始化参数
        List<Compute> computeList = initParams(formId, paramList, preVarsMap, preComputeMap, validate);
        //校验比对
        AtomicBoolean updateFieldType = new AtomicBoolean(false);
        Map<String, String> oldReferenceVarMap = new HashMap<>();
        if (!update){
            //新增
            List<ComputeParam> sumVarParamList = new ArrayList<>();
            //前置变量查询处理
            preVarHandle(formId, computeList, preVarsMap, preComputeMap, computeValueMap, columnVarMap, sumVarParamList, temp);
            saveOrUpdateComputeList(temp, computeList);
            //列求和变量处理
            calculateHandle(formId, sumVarParamList, true, temp, false);
            //列变量处理
            columnVarUpdateHandle(formId, columnVarMap, temp);
        }else {
            //更新
            computeList = compareCompute(formId, updateFieldType, preVarsMap, preComputeMap, oldReferenceVarMap, computeList, computeValueMap, temp);
            //前置变量查询处理
            preVarHandle(formId, computeList, preVarsMap, preComputeMap, computeValueMap, columnVarMap, null, temp);
            //后置变量查询处理
            sufVarHandle(formId, updateFieldType, preVarsMap, preComputeMap, oldReferenceVarMap, computeList, columnVarMap, temp);
        }
        return computeValueMap;
    }

    /**
     * 初始化所有列求和字段
     * @param formId 表单id
     */
    private void initColumnSumVar(Long formId) {
        List<Compute> sumVars = new ArrayList<>();
        List<Compute> columnSumVars = baseMapper.selectList(new LambdaQueryWrapper<Compute>()
                                                .eq(Compute::getFormId, formId)
                                                .isNull(Compute::getBusinessId)
                                                .eq(Compute::getDeleted, false));
        Map<String, Set<String>> columnSumVarMap = new HashMap<>();
        columnSumVars.forEach(var ->{
            Set<String> varList = columnSumVarMap.getOrDefault(var.getTableId(), new HashSet<>());
            varList.add(var.getVarFullName());
            columnSumVarMap.put(var.getTableId(), varList);
        });
        Date current = new Date();
        VariableContext.tableRelColumnSumVarMap.forEach((tableId, set) ->{
            Set<String> varList = columnSumVarMap.getOrDefault(tableId, new HashSet<>());
            set.forEach(varFullName ->{
                if (!varList.contains(varFullName)){
                    Variable variable = VariableContext.varMap.get(varFullName);
                    Compute compute = Compute.builder()
                                            .id(IdUtil.getSnowflakeNextId())
                                            .formId(formId)
                                            .tableId(tableId)
                                            .varType(VarTypeEnum.NUMBER)
                                            .var(variable.getName())
                                            .varValue(VarTypeEnum.NUMBER.defaultValue.toString())
                                            .varFullName(varFullName)
                                            .expression("")
                                            .createTime(current)
                                            .updateTime(current)
                                            .build();
                    sumVars.add(compute);
                }
            });
        });
        saveBatch(sumVars);
    }

    /**
     * 计算参数初始化
     *
     * @param formId
     * @param paramList
     * @param preVarsMap
     * @param preComputeMap
     * @param validate
     */
    private List<Compute> initParams(Long formId,
                                     List<ComputeParam> paramList,
                                     Map<String, List<String>> preVarsMap,
                                     Map<String, Compute> preComputeMap,
                                     boolean validate) {
        List<Compute> computeList = new ArrayList<>();
        paramList.forEach(param -> {
            if (validate){
                ValidationUtils.validateAndThrow(param);
            }
            Long id = param.getId() == null ? IdUtil.getSnowflakeNextId() : param.getId();
            VarTypeEnum varType = param.getVarType();
            String businessId = param.getBusinessId();
            String expression = param.getExpression();
            String varFullName = StrUtil.isNotBlank(businessId) ? ComputeUtils.getVarFullName(param.getVar(), businessId) : ComputeUtils.getColumnSumVarFullName(param.getTableId(), param.getVar(), false);
            Compute compute = Compute.builder()
                    .id(id)
                    .formId(formId)
                    .tableId(param.getTableId())
                    .businessId(businessId)
                    .varType(varType)
                    .var(param.getVar())
                    .varFullName(varFullName)
                    .expression(expression)
                    .originalExpression(param.getOriginalExpression())
                    .build();
            List<String> referenceVars = ComputeUtils.getVarFullNames(varType, expression);
            preVarsMap.put(compute.getVarFullName(), referenceVars);
            computeList.add(compute);
            preComputeMap.put(compute.getVarFullName(), compute);
        });
        return computeList;
    }

    /**
     * 校验比对
     *
     * @param formId
     * @param isUpdateFieldType
     * @param preVarsMap
     * @param preComputeMap
     * @param oldReferenceVarMap
     * @param computeList
     * @param computeValueMap 
     * @param temp 
     * @return
     */
    private List<Compute> compareCompute(Long formId, 
                                         AtomicBoolean isUpdateFieldType, 
                                         Map<String, List<String>> preVarsMap, 
                                         Map<String, Compute> preComputeMap, 
                                         Map<String, String> oldReferenceVarMap, 
                                         List<Compute> computeList, 
                                         Map<String, ComputeValue> computeValueMap, 
                                         boolean temp) {
        List<Compute> selfComputeList = baseMapper.listPreVars(formId, preComputeMap.keySet(), temp);
        Map<String, Compute> oldComputeMap = selfComputeList.stream().collect(Collectors.toMap(Compute::getVarFullName, Function.identity(), (v1, v2) -> v1));
        List<Compute> updateComputeList = new ArrayList<>(computeList);
        computeList.forEach(variable -> {
            String varFullName = variable.getVarFullName();
            Compute oldVariable = oldComputeMap.get(varFullName);
            Assert.notNull(oldVariable, MessageFormat.format("计算变量{0}不存在", varFullName));
            variable.setId(oldVariable.getId());
            isUpdateFieldType.set(!variable.getVarType().equals(oldVariable.getVarType()));
            String varValue = oldVariable.getVarValue();
            ComputeValue computeValue = ComputeValue.builder().newValue(varValue).oldValue(varValue).build();
            computeValueMap.put(variable.getVar(), computeValue);
            if (variable.getExpression().equals(oldVariable.getExpression()) && !isUpdateFieldType.get()) {
                variable.setVarValue(varValue);
                updateComputeList.remove(variable);
                preVarsMap.remove(varFullName);
                preComputeMap.remove(varFullName);
                return;
            }
            oldReferenceVarMap.put(varFullName, variable.getReferenceVar());
        });
        return updateComputeList;
    }

    /**
     * 前置变量查询处理
     *
     * @param formId
     * @param computeList
     * @param preVarsMap
     * @param preComputeMap
     * @param computeValueMap
     * @param columnVarMap
     * @param sumVarParamList
     * @param temp
     */
    private void preVarHandle(Long formId,
                              List<Compute> computeList,
                              Map<String, List<String>> preVarsMap,
                              Map<String, Compute> preComputeMap,
                              Map<String, ComputeValue> computeValueMap,
                              Map<String, Map<String, Object>> columnVarMap,
                              List<ComputeParam> sumVarParamList,
                              boolean temp) {
        Set<String> preVars = new HashSet<>();
        preVarsMap.values().forEach(preVars::addAll);
        if (!CollectionUtils.isEmpty(preVars)) {
            List<Compute> computes = baseMapper.listPreVars(formId, preVars, temp);
            computes.forEach(compute -> {
                preComputeMap.putIfAbsent(compute.getVarFullName(), compute);
            });
        }
        Map<String, List<Compute>> tableRefRowSumVarMap = new HashMap<>();
        computeList.forEach(compute -> {
            String var = compute.getVar();
            String varFullName = compute.getVarFullName();
            List<String> varList = preVarsMap.get(varFullName);
            List<String> finalVarList = new ArrayList<>(varList);
            VarTypeEnum varType = compute.getVarType();
            Map<String, Object> varMap = new HashMap<>();
            varList.forEach(preVar -> {
                //是否为列计算变量
                if (VariableContext.columnVarMap.keySet().contains(preVar)) {
                    varMap.put(preVar, new HashMap<>());
                    return;
                }
                //是否为列求和计算变量
                if (VariableContext.tableRelColumnSumVarMap.get(compute.getTableId()).contains(preVar)) {
                    varMap.put(preVar, preVar);
                    return;
                }
                Compute preCompute = preComputeMap.get(preVar);
                Assert.notNull(preCompute, MessageFormat.format("计算变量{0}不存在", preVar));
                varMap.put(preVar, preCompute.getVarValue());
                String referenceVar = preCompute.getReferenceVar();
                if (StrUtil.isNotBlank(referenceVar)) {
                    List<String> referenceVarList = Arrays.asList(referenceVar.split(StrUtil.COMMA));
                    Assert.state(!referenceVarList.contains(varFullName), "存在循环引用，计算公式中直接或间接地引用其本身，这会导致计算不正确");
                    finalVarList.addAll(referenceVarList);
                }
            });
            //列求和变量处理
            columnSumVarHandle(formId, compute, tableRefRowSumVarMap, sumVarParamList);
            //列变量处理
            preColumnVariableHandle(formId, varMap);
            preVarsMap.put(varFullName, finalVarList);
            String fieldValue = ComputeUtils.execute(varType, varMap, compute.getExpression());
            ComputeValue computeValue = computeValueMap.getOrDefault(var, new ComputeValue());
            computeValue.setNewValue(fieldValue);
            computeValueMap.put(var, computeValue);
            String referenceVar = finalVarList.isEmpty() ? null : String.join(StrUtil.COMMA, finalVarList);
            String valueMapStr = varMap.isEmpty() ? null : JSONUtil.toJsonStr(varMap);
            compute.setReferenceValueMap(valueMapStr).setVarValue(fieldValue).setReferenceVar(referenceVar);
            judgeOfColumnField(compute, columnVarMap);
        });
    }

    /**
     * 前置变量中列计算处理
     *
     * @param formId   表单id
     * @param fieldMap 变量集
     */
    private void preColumnVariableHandle(Long formId, Map<String, Object> fieldMap) {
        Map<String, List<Variable>> columnVariables = VariableContext.getColumnVarMap(fieldMap.keySet());
        if (columnVariables.isEmpty()) {
            return;
        }
        columnVariables.forEach((tableId, variables) -> {
            ColumnVarHandle columnVarHandle = ColumnVarHandleFactory.getHandle(tableId);
            if (columnVarHandle == null){
                log.warn("列变量所属表格{}的未实现ColumnVarHandle处理类", tableId);
                return;
            }
            columnVarHandle.injectReferenceValue(formId, variables, fieldMap);
        });
    }

    /**
     * 后置变量查询处理
     *
     * @param formId
     * @param isUpdateFieldType
     * @param preVarsMap
     * @param preComputeMap
     * @param oldReferenceVarMap
     * @param computeList
     * @param columnVarMap
     * @param temp
     */
    private void sufVarHandle(Long formId,
                              AtomicBoolean isUpdateFieldType,
                              Map<String, List<String>> preVarsMap,
                              Map<String, Compute> preComputeMap,
                              Map<String, String> oldReferenceVarMap,
                              List<Compute> computeList,
                              Map<String, Map<String, Object>> columnVarMap,
                              boolean temp) {
        Set<String> preVars = preVarsMap.keySet();
        if (CollectionUtil.isEmpty(preVars)){
            saveOrUpdateComputeList(temp, computeList);
            return;
        }
        List<Compute> sufComputeList = baseMapper.listSufVars(formId, preVars, temp);
        if (CollectionUtil.isEmpty(sufComputeList)) {
            saveOrUpdateComputeList(temp, computeList);
            return;
        }
        Assert.state(!isUpdateFieldType.get(), "当前计算变量已被引用计算，变更变量值类型前需要先移除引用");
        handleRowCompute(preVarsMap, preComputeMap, oldReferenceVarMap, computeList, sufComputeList, columnVarMap);
        saveOrUpdateComputeList(temp, computeList);
        //更新引用列变量的变量
        columnVarUpdateHandle(formId, columnVarMap, temp);
    }

    /**
     * 保存计算变量
     * @param temp
     * @param computeList
     */
    private void saveOrUpdateComputeList(boolean temp, List<Compute> computeList) {
        if (temp) {
            saveOrUpdateBatchTemp(computeList);
        } else {
            saveOrUpdateBatch(computeList);
        }
    }

    /**
     * 保存临时计算变量
     * @param computeList
     */
    private void saveOrUpdateBatchTemp(List<Compute> computeList) {
        List<ComputeTemp> computeTempList = BeanUtil.copyToList(computeList, ComputeTemp.class);
        computeTempService.saveOrUpdateBatch(computeTempList);
    }

    /**
     * 处理行计算字段
     *
     * @param preVarsMap
     * @param preComputeMap
     * @param oldReferenceVarMap
     * @param computeList
     * @param sufComputeList
     * @param columnVarMap
     */
    private void handleRowCompute(Map<String, List<String>> preVarsMap,
                                  Map<String, Compute> preComputeMap,
                                  Map<String, String> oldReferenceVarMap,
                                  List<Compute> computeList,
                                  List<Compute> sufComputeList,
                                  Map<String, Map<String, Object>> columnVarMap) {
        sufComputeList.sort(Comparator.comparingInt(variable -> Optional.ofNullable(variable.getReferenceVar()).map(str -> str.split(StrUtil.COMMA).length).orElse(0)));
        sufComputeList.forEach(variable -> {
            String varFullName = variable.getVarFullName();
            // 避免循环引用导致无法修改
            if (preComputeMap.containsKey(varFullName)) {
                return;
            }
            Map<String, Object> referenceValueMap = new HashMap<>();
            String referenceValueMapStr = variable.getReferenceValueMap();
            if (StrUtil.isNotBlank(referenceValueMapStr)) {
                referenceValueMap = JSONUtil.toBean(referenceValueMapStr, Map.class);
                referenceValueMap.replaceAll((k, v) -> {
                    Compute suf = preComputeMap.get(k);
                    return suf == null ? v : suf.getVarValue();
                });
            }
            preColumnVariableHandle(variable.getFormId(), referenceValueMap);
            String varValue = ComputeUtils.execute(variable.getVarType(), referenceValueMap, variable.getExpression());
            String referenceVar = variable.getReferenceVar();
            List<String> referenceVarList = new ArrayList<>(Optional.ofNullable(referenceVar).map(str -> Arrays.asList(str.split(StrUtil.COMMA))).orElse(new ArrayList<>()));
            //移除引用变量中旧的变量集并添加新的变量集
            oldReferenceVarMap.keySet().forEach(key -> {
                if (referenceVarList.contains(key)) {
                    String oldFieldBusinessId = oldReferenceVarMap.get(key);
                    List<String> oldFields = Optional.ofNullable(oldFieldBusinessId).map(s -> Arrays.asList(oldFieldBusinessId.split(StrUtil.COMMA))).orElse(new ArrayList<>());
                    referenceVarList.removeAll(oldFields);
                    referenceVarList.addAll(preVarsMap.get(key));
                }
            });
            referenceVar = referenceVarList.isEmpty() ? null : String.join(StrUtil.COMMA, referenceVarList);
            referenceValueMapStr = referenceValueMap.isEmpty() ? null : JSONUtil.toJsonStr(referenceValueMap);
            variable.setReferenceValueMap(referenceValueMapStr).setVarValue(varValue).setReferenceVar(referenceVar);
            preComputeMap.put(varFullName, variable);
            computeList.add(variable);
            judgeOfColumnField(variable, columnVarMap);
        });
    }

    /**
     * 判断更新的计算行变量是否属于计算列变量中
     *
     * @param compute
     * @param columnVarMap
     */
    private void judgeOfColumnField(Compute compute, Map<String, Map<String, Object>> columnVarMap) {
        String columnVarFullName = ComputeUtils.getColumnVarFullName(compute.getTableId(), compute.getVar());
        Variable variable = VariableContext.columnVarMap.get(columnVarFullName);
        if (variable != null) {
            Map<String, Object> columnVarValueMap = columnVarMap.getOrDefault(columnVarFullName, new HashMap<>());
            columnVarValueMap.put(compute.getBusinessId(), compute.getVarValue());
            columnVarMap.put(columnVarFullName, columnVarValueMap);
        }
    }

    /**
     * 后置引用变量处理 - 变量删除情况
     *
     * @param rowSumVars       汇总字段集合
     * @param preVars       前置变量名集合
     * @param preComputeMap 前置变量map
     * @param sufComputeList   后置引用变量集合
     */
    private void sufVarDeleteHandle(Set<String> rowSumVars,
                                    Set<String> preVars,
                                    Map<String, Compute> preComputeMap,
                                    List<Compute> sufComputeList,
                                    List<Compute> computeList) {
        sufComputeList.sort(Comparator.comparingInt(compute -> Optional.ofNullable(compute.getReferenceVar()).map(str -> str.split(StrUtil.COMMA).length).orElse(0)));
        sufComputeList.forEach(compute -> {
            String varFullName = compute.getVarFullName();
            if (preComputeMap.containsKey(varFullName)) {
                return;
            }
            String expression = compute.getExpression();
            Map<String, Object> referenceValueMap = JSONUtil.toBean(compute.getReferenceValueMap(), Map.class);
            if (rowSumVars.contains(varFullName)) {
                //删除汇总变量公式中引用的变量
                expression = deleteVarInExpression(expression, preVars, referenceValueMap);
            } else {
                rowSumVarReferenceHandle(compute.getTableId(), expression, preVars, referenceValueMap, preComputeMap);
            }
            computeResultHandle(varFullName, compute, expression, referenceValueMap, preVars, preComputeMap, computeList);
        });
    }

    /**
     * 删除汇总变量公式中引用的变量
     *
     * @param expression
     * @param preVars
     * @param referenceValueMap
     * @return
     */
    private String deleteVarInExpression(String expression, Set<String> preVars, Map<String, Object> referenceValueMap) {
        List<String> variables = new ArrayList<>(Arrays.asList(expression.split("\\" + OperatorType.ADD.token)));
        preVars.forEach(preVar -> {
            variables.remove(preVar);
            referenceValueMap.remove(preVar);
        });
        if (variables.isEmpty()){
            return VarTypeEnum.NUMBER.defaultValue.toString();
        }
        return String.join(OperatorType.ADD.token, variables);
    }

    /**
     * 引用汇总的计算字段处理
     *
     * @param tableId
     * @param expression
     * @param preVars
     * @param referenceValueMap
     * @param preComputeMap
     */
    private void rowSumVarReferenceHandle(String tableId,
                                          String expression,
                                          Set<String> preVars,
                                          Map<String, Object> referenceValueMap,
                                          Map<String, Compute> preComputeMap) {
        String tableName = VariableContext.tableMap.get(tableId);
        preVars.forEach(preVar -> {
            Assert.state(!expression.contains(preVar), "计算变量已被'" + tableName + "'中引用计算，需要移除引用后才能删除");
        });
        referenceValueMap.forEach((k, v) -> {
            if (preComputeMap.containsKey(k)) {
                referenceValueMap.put(k, preComputeMap.get(k).getVarValue());
            }
        });
    }

    /**
     * 计算参数结果处理
     *
     * @param varFullName
     * @param compute
     * @param expression
     * @param referenceValueMap
     * @param preVars
     * @param preComputeMap
     * @param computeList
     */
    private void computeResultHandle(String varFullName,
                                     Compute compute,
                                     String expression,
                                     Map<String, Object> referenceValueMap,
                                     Set<String> preVars,
                                     Map<String, Compute> preComputeMap,
                                     List<Compute> computeList) {
        String varValue = ComputeUtils.execute(compute.getVarType(), referenceValueMap, expression);
        String referenceVar = compute.getReferenceVar();
        List<String> referenceVarList = new ArrayList<>(Arrays.asList(referenceVar.split(StrUtil.COMMA)));
        preVars.forEach(preVar -> {
            if (!referenceVarList.contains(preVar)) {
                return;
            }
            String oldReferenceVar = preComputeMap.get(preVar).getReferenceVar();
            List<String> oldVarList = new ArrayList<>();
            if (StrUtil.isNotBlank(oldReferenceVar)){
                oldVarList.addAll(Arrays.asList(oldReferenceVar.split(StrUtil.COMMA)));
            }
            oldVarList.add(preVar);
            referenceVarList.removeAll(oldVarList);
        });
        referenceVar = referenceVarList.isEmpty() ? null : String.join(StrUtil.COMMA, referenceVarList);
        String referenceValueMapStr = referenceValueMap.isEmpty() ? null : JSONUtil.toJsonStr(referenceValueMap);
        compute.setReferenceValueMap(referenceValueMapStr)
                .setExpression(expression)
                .setVarValue(varValue)
                .setReferenceVar(referenceVar);
        preComputeMap.put(varFullName, compute);
        computeList.add(compute);
    }

    /**
     * 列变量处理
     * @param formId
     * @param columnVarMap
     * @param temp
     */
    public void columnVarUpdateHandle(Long formId, Map<String, Map<String, Object>> columnVarMap, boolean temp) {
        columnVarUpdateHandle(formId, columnVarMap, false, null, temp);
    }

    /**
     * 列变量处理
     *
     * @param formId
     * @param columnVarMap
     * @param isDelete  是否删除，变量删除情况
     * @param businessIdsStr
     * @param temp
     * @return
     */
    private void columnVarUpdateHandle(Long formId,
                                       Map<String, Map<String, Object>> columnVarMap,
                                       boolean isDelete,
                                       Set<String> businessIdsStr,
                                       boolean temp) {
        Set<String> columns = new HashSet<>();
        columns.addAll(columnVarMap.keySet());
        if (columns.isEmpty()) {
            return;
        }
        List<Compute> computeList = baseMapper.listSufVars(formId, columns, temp);
        if (CollectionUtils.isEmpty(computeList)) {
            return;
        }
        computeList.sort(Comparator.comparingInt(compute -> Optional.ofNullable(compute.getReferenceVar()).map(str -> str.split(StrUtil.COMMA).length).orElse(0)));
        Map<String, Compute> preComputeMap = new HashMap<>();
        Map<String, Map<String, Object>> columnFieldMap = new HashMap<>();
        for (Compute compute : computeList) {
            String varFullName = compute.getVarFullName();
            //多级引用缓存
            Map<String, Object> referenceValueMap = JSONUtil.toBean(compute.getReferenceValueMap(), Map.class);
            referenceValueMap.keySet().forEach(key -> {
                Compute variable = preComputeMap.get(key);
                if (variable != null) {
                    referenceValueMap.put(key, variable.getVarValue());
                }
            });
            //列计算字段变量更新
            columns.forEach(column -> {
                Object variable = referenceValueMap.get(column);
                if (variable == null) {
                    return;
                }
                Map<String, Object> valueMap = (Map<String, Object>) variable;
                if (isDelete) {
                    businessIdsStr.forEach(businessIdStr ->{
                        valueMap.remove(businessIdStr);
                    });
                }else {
                    valueMap.putAll(columnVarMap.get(column));
                }
            });
            String varValue = ComputeUtils.execute(compute.getVarType(), referenceValueMap, compute.getExpression());
            String referenceValueMapStr = referenceValueMap.isEmpty() ? null : JSONUtil.toJsonStr(referenceValueMap);
            compute.setReferenceValueMap(referenceValueMapStr).setVarValue(varValue);
            preComputeMap.put(varFullName, compute);
            judgeOfColumnField(compute, columnFieldMap);
        }
        if (CollectionUtil.isNotEmpty(computeList)) {
            deleteBatchByIds(temp, computeList);
        }
        recursiveHandle(formId, preComputeMap, columnFieldMap, temp);
    }

    /**
     * 递归处理列函数变化
     *
     * @param formId
     * @param preComputeMap
     * @param columnFieldMap
     * @param temp
     */
    private void recursiveHandle(Long formId,
                                 Map<String, Compute> preComputeMap,
                                 Map<String, Map<String, Object>> columnFieldMap,
                                 boolean temp) {
        List<Compute> sufCalculates = baseMapper.listSufVars(formId, preComputeMap.keySet(), temp);
        if (!CollectionUtils.isEmpty(sufCalculates)) {
            List<Compute> computeList = new ArrayList<>();
            handleRowCompute(null, preComputeMap, new HashMap<>(), computeList, sufCalculates, columnFieldMap);
            saveOrUpdateComputeList(temp, computeList);
        }
        if (CollectionUtil.isNotEmpty(columnFieldMap)) {
            columnVarUpdateHandle(formId, columnFieldMap, temp);
        }
    }

}
